package com.base.cn.platform.os.common.utils.pay;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.base.cn.platform.os.common.utils.order.GenerateOrderNum;
import com.base.cn.platform.os.common.utils.pay.config.ZFBConfig;
import com.base.cn.platform.os.common.utils.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 支付宝工具类
 *
 * @author s.li
 * @create 2018-09-12-9:50
 */
@Slf4j
public class AlipayUtils extends PayService{


    /**
     * 交易创建，等待买家付款
     */
    private  String  WAIT_BUYER_PAY ="WAIT_BUYER_PAY";
    /**
     * 未付款交易超时关闭，或支付完成后全额退款
     */
    private  String  TRADE_CLOSED ="TRADE_CLOSED";
    /**
     * 交易成功
     */
    private  String  TRADE_SUCCESS ="TRADE_SUCCESS";
    /**
     * 交易结束，不可退款
     */
    private  String  TRADE_FINISHED ="TRADE_FINISHED";


    @Override
    public Map<String,Object> goToPay(HttpServletRequest request,
                                      Map<String, String> payConfigMap,
                                      Map<String, String> params,
                                      String clientType) throws Exception {
        String resultContext = null;
        if(clientType.equals(PayFormClient.PC)){
            resultContext = this.goZFBWeb(payConfigMap,params);
        }
        if(clientType.equals(PayFormClient.H5)){
            resultContext = this.goZFBMobile(payConfigMap,params);
        }
        if(clientType.equals(PayFormClient.ANDROID) || clientType.equals(PayFormClient.IOS)){
            resultContext = this.goZFBApp(payConfigMap,params);
        }
        return ResultUtil.SUCCESS("操作成功",resultContext);
    }

    @Override
    public Map<String, String> payCallback(HttpServletRequest request,
                                           HttpServletResponse response,
                                           Map<String, String> payConfigMap,
                                           String clientType) throws Exception{
        Map<String,String> resultMap = new HashMap<>();
        resultMap.put("success","false");
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();

        Enumeration<String> requestParams = request.getParameterNames();
        while (requestParams.hasMoreElements()){
            String name = requestParams.nextElement();
            String value = request.getParameter(name);
            params.put(name, value);
        }
        /*for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name =  iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }*/
        //获取支付宝配置
        String publicKey = payConfigMap.get("publicKey");//公钥
        log.info("---------------------params:"+params);
        //验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, publicKey, ZFBConfig.input_charset, ZFBConfig.sign_type); //调用SDK验证签名
        log.info("------------------------签名状态 signVerified:"+signVerified);
        //——请在这里编写您的程序（以下代码仅作参考）——
            /* 实际验证过程建议商户务必添加以下校验：
            1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
            2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
            3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
            4、验证app_id是否为该商户本身。
            */
        if(signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            log.info("-----------------out_trade_no:"+out_trade_no);
            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
            log.info("-----------------trade_no:"+trade_no);
            //支付金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
            //支付状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
            //如果交易成功 和 交易完成不可退款 支付状态为true
            if(trade_status.equals(TRADE_SUCCESS)){
                resultMap.put("success","true");
            }else{
                resultMap.put("success","false");
            }
            resultMap.put("amount",total_amount);
            resultMap.put("treadNo",trade_no);
            //付款完成后，支付宝系统发送该交易状态通知
            response.getWriter().print("success");
        }else{
            resultMap.put("success","false");
            response.getWriter().print("fail");
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> payTransfer(HttpServletRequest request,
                                           TreeMap<String, String> payConfigMap,
                                           Map<String, String> params) throws Exception{
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                payConfigMap.get("alipaypartnerID"),
                payConfigMap.get("privateKey"),
                ZFBConfig.format,
                ZFBConfig.input_charset,
                payConfigMap.get("publicKey"),
                ZFBConfig.sign_type);
        AlipayFundTransToaccountTransferRequest transferRequest = new AlipayFundTransToaccountTransferRequest();
        Map<String,String> bizContentMap = new LinkedHashMap<>();
        //商户转账唯一订单号。发起转账来源方定义的转账单据ID，用于将转账回执通知给来源方
        bizContentMap.put("out_biz_no", GenerateOrderNum.getInstance().generateOrderNo());
        //ALIPAY_LOGONID 支付宝登录号，支持邮箱和手机号格式
        //ALIPAY_USERID 支付宝账号对应的支付宝唯一用户号。以2088开头的16位纯数字组成。
        bizContentMap.put("payee_type","ALIPAY_LOGONID");
        //收款方账户(必选)
        bizContentMap.put("payee_account",params.get("account"));
        //转账金额 单位：元(必选)
        bizContentMap.put("amount",params.get("amount"));
        //付款方姓名(可选)
        bizContentMap.put("payer_show_name",params.get("payerShowName"));
        //收款方真实姓名(可选)
        bizContentMap.put("payee_real_name",params.get("realName"));
        //转账备注(可选)（支持200个英文/100个汉字）
        bizContentMap.put("remark",params.get("remark"));
        String bizContentStr = gson.toJson(bizContentMap);
        transferRequest.setBizContent(bizContentStr);
        AlipayFundTransToaccountTransferResponse transferResponse = alipayClient.execute(transferRequest);
        if(transferResponse.isSuccess()){
            return ResultUtil.SUCCESS();
        }else{
            String message = transferResponse.getSubMsg();
            log.info("==============message:"+message);
            log.info("==============error code:"+transferResponse.getSubCode());
            return ResultUtil.ERROR(message);
        }
    }

    //=============================================================
    /**
     * PC支付宝支付
     * @param payConfigMap 支付类型的配置数据
     * @param params 订单、回调路径、用户信息等数据参数
     * @throws Exception
     */
    private String goZFBWeb(Map<String, String> payConfigMap,
                            Map<String, String> params) throws Exception{
        AlipayClient alipayClient = getAlipayClient(payConfigMap);
        //设置请求参数
        AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
        //获取业务参数
        String bizContent = this.getBizContext(params);
        alipayTradePagePayRequest.setNotifyUrl(params.get("notifyUrl"));//设置回调路径
        alipayTradePagePayRequest.setReturnUrl(params.get("returnUrl"));//设置回调路径
        alipayTradePagePayRequest.setBizContent(bizContent);
        //请求
        String result = alipayClient.pageExecute(alipayTradePagePayRequest).getBody();
        return result;
    }

    /**
     * H5支付宝支付
     * @param payConfigMap 支付类型的配置数据
     * @param params 订单、回调路径、用户信息等数据参数
     * @return 返回的是一个HTML字符串的from表单
     * @throws Exception
     */
    private String goZFBMobile(Map<String, String> payConfigMap,
                               Map<String, String> params) throws Exception{
        AlipayClient alipayClient = getAlipayClient(payConfigMap);
        //设置请求参数
        AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
        //获取业务参数
        String bizContent = this.getBizContext(params);
        alipayTradeWapPayRequest.setNotifyUrl(params.get("notifyUrl"));//设置回调路径
        alipayTradeWapPayRequest.setReturnUrl(params.get("returnUrl"));//设置回调路径
        alipayTradeWapPayRequest.setBizContent(bizContent);
        //请求页面内容
        String from = alipayClient.pageExecute(alipayTradeWapPayRequest).getBody();
        return from;
    }

    /**
     * App支付宝支付
     * @param payConfigMap 支付类型的配置数据
     * @param params 订单、回调路径、用户信息等数据参数
     * @return 返回的是一个HTML字符串的from表单
     * @throws Exception
     */
    private String goZFBApp(Map<String, String> payConfigMap,
                            Map<String, String> params) throws Exception{
        AlipayClient alipayClient = getAlipayClient(payConfigMap);
        //设置请求参数
        AlipayTradeAppPayRequest alipayTradeAppPayRequest = new AlipayTradeAppPayRequest();

        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(params.get("describe"));
        model.setSubject(params.get("describe"));
        String outTradeNo = getOutTradeNo(params);
        model.setOutTradeNo(outTradeNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(params.get("totalAmount"));
        model.setProductCode("QUICK_MSECURITY_PAY");
        alipayTradeAppPayRequest.setBizModel(model);
        alipayTradeAppPayRequest.setNotifyUrl(params.get("notifyUrl"));
        //就是orderString 可以直接给客户端请求，无需再做处理。
        String orderString = alipayClient.sdkExecute(alipayTradeAppPayRequest).getBody();
        log.info("app orderString:"+orderString);
        return orderString;
    }

    /**
     * 通过支付配置获取 AlipayClient对象
     * @param payConfigMap 支付宝配置
     * @return AlipayClient
     */
    private AlipayClient getAlipayClient(Map<String,String> payConfigMap){
        //支付宝应用ID
        String appId = payConfigMap.get("alipaypartnerID");
        String publicKey = payConfigMap.get("publicKey");//支付宝公钥
        String privateKey = payConfigMap.get("privateKey");//支付宝私钥
        AlipayClient alipayClient = new DefaultAlipayClient(ZFBConfig.gatewayUrl,appId,privateKey,ZFBConfig.format,ZFBConfig.input_charset,publicKey,ZFBConfig.sign_type);
        return alipayClient;
    }

    /**
     * 获取业务内容
     * @param params 订单、回调路径、用户信息等数据参数
     * @return 支付内容
     */
    private String getBizContext(Map<String,String> params) {
        String outTradeNo = getOutTradeNo(params);
        //业务数据内容
        //商户订单号，商户网站订单系统中唯一订单号，必填 out_trade_no
        //付款金额，必填 total_amount
        //订单名称，必填  subject
        //商品描述，可空  body
        String bizContent = "{'out_trade_no':'"+outTradeNo+"','total_amount':'"+params.get("totalAmount")+"','subject':'" + params.get("describe") + "','body':'" + params.get("describe") + "','product_code':'FAST_INSTANT_TRADE_PAY'}";
        return bizContent;
    }
}
